(function() {

    var common = {},
        win = window,
        localStr = (localStorage && localStorage.getItem("ivData")) || "{}",
        /**
         * @var {object}
         */
        localData = JSON.parse(localStr),
        /**
         * @property LOCAL_DATA_SIZE
         * @desc 本地存储的单条数据大小
         * @type {number}
         */
        LOCAL_DATA_SIZE = 1000 * 200,
        /**
         * @property EXPIRE_TIME
         * @desc 本地存储的默认有效期为一个小时
         * @type {number}
         */
        EXPIRE_TIME = 1000 * 60 * 60;

    /**
     * @private
     * @func isCache
     * @desc 判断是否开启了nocache
     * @returns {boolean}
     */
    common.isCache = function () {
        var urlCache = location.href.indexOf("nocache") === -1;
        if (!localStorage) {
            return false;
        }
        var localFlag = localStorage.getItem("isInitCache");
        if (!localFlag && urlCache) {
            localStorage.setItem("isInitCache", "true");
        }
        if (!urlCache) {
            localStorage.removeItem("isInitCache");
        }
        return urlCache;
    };

    /**
     * @checkLocal
     * @desc 检测本地存储是否有相应的数据
     * @param key 本地存储里对应的key
     * @param expireTime 失效时间
     * @returns {string|null} 如果本地存储存在,并且时间有效,则返回数据
     */
    common.checkLocal = function (key, expireTime) {
        var data = localData[key];
        if (common.isExpire(data, expireTime)) {
            return data;
        }
    };

    /**
     * @func saveLocal
     * @desc 保存数据到localStorage里
     * @param {string} key 索引值
     * @param {object|string} data 数据
     */
    common.saveLocal = function (key, data) {
        var now = new Date().getTime();
        localData[key] = {
            time: now,
            data: data
        };
    };
    /**
     * @func isExpire
     * @desc 判断本地数据是否有效
     * @param {object} _data 本地的数据
     * @param {object} _data.data 本地数据
     * @param {int} _data.time 本地数据被保存的时间
     * @param {int} _expireTime 失效的时间//也可以是布尔值
     * @param {string|number} [_data.data.State] 接口状态值,如果为300,则标记为请求失败,则不保存
     * @returns {boolean|*}
     */
    common.isExpire = function (_data, _expireTime) {
        if (!_data) {
            return false;
        }
        var now = new Date().getTime(),
            _stamp = _data.time,
            data = _data.data;
        if (_expireTime && (typeof(_expireTime)).toLowerCase() === "boolean") {
            return !_expireTime;
        }
        //当缓存时间不超过1天，并且没有使用强制刷新，并且返回的状态不为300（请求失败）时,走本地存储
        return (now - _stamp <= (_expireTime || EXPIRE_TIME) && !(data.State === "300" || data.state === 300) &&
        common.isCache());
    };

    /**
     *  不带缓存的异步请求
     * @param  {[type]}   url      [description]
     * @param  {Function} callback [description]
     * @return {[type]}            [description]
     */
    common.ajax = function (url, callback) {
        $.ajax({
            type: 'GET',
            url: url,
            cache: false,
            // data to be added to query string:
            // type of data we are expecting in return:
            dataType: 'jsonp',
            success: function (data) {
                callback(data);
            }
        });
    }
    /**
     * @func getData
     * @desc 异步获取数据
     * @param {string} url 异步请求的地址
     * @param {function} callback 回调函数
     * @param {(int|boolean)} [_expireTime] 失效的时间,单位为毫秒//也可以是布尔值
     * @returns {boolean}
     * @example
     * //请求数据时,默认情况下为一个小时缓存
     * Common.getData("/test",function(data){})
     * //请求数据时不走缓存
     * Common.getData("/test",function(data){},true)
     *
     * //请求数据时,缓存半个小时
     * Common.getData("/test",function(data){},1000*60*30)
     */
    common.getData = function (url, callback, _expireTime) {
        var encodeUrl = encodeURIComponent(url),
            _data = localData[encodeUrl];
        if (_data) {
            //当缓存时间不超过1天，并且没有使用强制刷新，并且返回的状态不为300（请求失败）时,走本地存储
            if (common.isExpire(_data, _expireTime)) {
                callback.call(this, _data.data);
                return false;
            } else {
                localData[encodeUrl] = null;
            }
        }
        $.ajax({
            type: "GET",
            url: url,
            dataType: "jsonp",
            contentType: "application/x-www-form-urlencoded; charset=UTF-8",
            success: function (data) {
                if (!data) {
                    window.Monitor.log("接口错误！" + url, "interface");
                    return;
                }
                if (!(data.State === "300" || data.state === 300)) {
                    common.saveLocal(encodeUrl, data);
                }
                try {
                    $.isPlainObject(data);
                } catch (e) {
                    // console.log ie8下会报错
//                    console.log("数据解析错误!");
                    return;
                }
                callback.apply(this, arguments);
            },
            error: function () {
                var prefix = "";
                if (url.indexOf("http") === -1) {
                    prefix = "//" + location.host;
                }
                Monitor.log(prefix + url, "interface");
            }
        });

    };

    /**
     * @func backPage
     * @desc 页面后退,在后退事件里调用这个方法
     * @returns {boolean}
     */
    common.backPage = function () {
        var self = this, pages = self.pages, previous, current;
        var currentCfg, _page;
        do {
            currentCfg = pages.pop();
            _page = pages[pages.length - 1];
        } while (pages.length > 1 && currentCfg.url === _page.url && currentCfg.tag === _page.tag && currentCfg.title === _page.title && !_page.el);
        if (currentCfg) {
            current = self.getPage(currentCfg.tag).removeClass("current").removeClass("switching");
        }

        var prevCfg = pages[pages.length - 1];
        if (!prevCfg) {
            return true;
        }
        previous = self.getPage(prevCfg.tag);
        previous.addClass("current").addClass("switching");
        common.setTitle(prevCfg.title);
        if (win.history.replaceState) {
            win.history.replaceState(null, prevCfg.title || "", prevCfg.url);
        }
        setTimeout(function () {
            if (current) {
                current.css({display: "none"});
            }
            previous.css({display: "block"});
            $(win).scrollTop(current.data("scrollTop"));
            currentCfg.callback && currentCfg.callback();
            currentCfg.el && currentCfg.el.trigger("trigger");
        }, 200);
    };
    /**
     * @private
     * @func initPage
     * @desc 初始化page组件
     */
    common.initPage = function () {
        var self = this;
        win.addEventListener("popstate", function (e) {
            common.backPage(e);
        });
        self.titleEl = ".page-header h2";
        self.pages = [];
    };

    /**
     * @func setTitle
     * @desc 设置标题
     * @param {string} [text="默认标题"]
     */
    common.setTitle = function (text) {
        var titleEl = $(this.titleEl);
        if (titleEl) {
            titleEl.text(text || "默认标题");
        }
    };
    /**
     * @private
     * @func getPage
     * @desc 根据tag生成对应的容器
     * @param tag String 标签名称
     * @returns {*|HTMLElement}
     */
    common.getPage = function (tag) {
        var el = $("#" + tag + "Page");
        if (!el.length) {
            var wrap = $(".page-box");
            wrap.length < 1 && (wrap = $("body"));
            el = $('<div class="page" id="' + tag + 'Page"></div>').appendTo(wrap);
        }
        return el;
    };

    /**
     * @private
     * @func forwardPage
     * @desc 页面前进
     * @param {object} cfg 配置
     */
    common.forwardPage = function (cfg) {
        var self = this, pages = self.pages, previous, current, tag = cfg.tag, prevCfg;
        prevCfg = pages[pages.length - 1];
        if (prevCfg) {
            previous = self.getPage(prevCfg.tag).data("scrollTop", $(win).scrollTop());
            previous.removeClass("current").removeClass("switching");
        }

        current = self.getPage(tag);
        common.setTitle(cfg.title);

        current.css({display: "block"}).addClass("switching");
        $(win).scrollTop(0); // 可以通过动画实现可流畅的效果
        if (!prevCfg || (prevCfg.tag !== cfg.tag)) {
            setTimeout(function () {
                current.addClass("current").css("display", "block");
                current.removeAttr("style");
                if (previous) {
                    previous.css({display: "none"});
                }
            }, 200);
        }

    };
    /**
     * @private
     * @func togglePage
     * @desc 页面配置切换
     * @param cfg
     * @param {object} cfg.tag 跳转目标页面的标签
     * @param {*} cfg.el 如果有el,则当触发后退时,会点击该按钮
     * @param {string} cfg.title 设置跳转目标页面的title
     * @param {function} cfg.callback 回调方法
     */
    common.togglePage = function (cfg) {
        var tag = cfg.tag,
            title = $(this.titleEl).text(),
            pages = this.pages;
        pages.push({
            "tag": tag,
            "title": title,
            el: cfg.el,
            url: cfg.url,
            callback: cfg.callback
        });
    };

    /**
     * @func redirect
     * @desc 该方法用来跳转页面，页面切换的方法
     * @param {object} cfg 跳转页面的配置
     * @param {object} cfg.tag 跳转目标页面的标签
     * //如: cfg.tag = "test",那么会判断是否有id="testPage"的页面,如果没有则创建,然后切换到该页面
     * //一般是用来配合{@link module:Common.render}渲染了那个testPage页面后,再切换过去
     * @param {object} cfg.title 设置跳转目标页面的title
     * @example
     * Common.redirect({
 *     tag: "calendar",
 *     title: "选择日期",
 *     callback: function(){}
 * })
     */
    common.redirect = function (cfg, extraCfg) {

        if ($("#commonDownloadClose").length > 0) {
            $("body").addClass("has-download-ads");
        }
        if ($(".page-header").length > 0) {
            $("body").addClass("has-header");
        }
        var url = cfg.url || "",
            tag = cfg.tag,
            param = cfg.param || {};
        if (!extraCfg) {
            if (win.history.pushState) {
                win.history.pushState(param, cfg.title || "", url);
            }
        }

        common.forwardPage(cfg);
        if (!extraCfg) {
            this.togglePage(cfg);
        }
    };

    /**
     * @func renderHtml
     * @desc 将tmpl插入到context里
     * @param {string} tmpl 模板生成的html字符串
     * @param {string} context 选择器
     */
    common.renderHtml = function (tmpl, context) {
        var contentEl = $(context);
        $(tmpl).appendTo(contentEl);
    };

    /**
     * @func render
     * @desc 页面渲染
     * @param {object} cfg
     * @param {object} cfg.tmpl dotjs的模板对象
     * @param {object} cfg.data 渲染模板所需要数据
     * @param {string} cfg.context 渲染的模板将被插入的容器选择器
     * @param {function} cfg.callback 渲染完成的回调方法
     * @param {boolean} [cfg.overwrite] 是否清空容器原有内容
     * @example
     * @copyright [zxy] 模板使用的是template
     * var tmpl = require("tpl/index/index");
     */
    common.render = function (cfg) {
        var self = this,
            tmpl = cfg.tmpl,
            data = cfg.data,
            key = cfg.key,
            context = cfg.context,
            callback = cfg.callback;
        var _data = data[key] || data;
        //附加一个key的变量用来控制脚本
        _data.key = key;
        var sel = ".J_" + key;
        var el = $(sel);
        if (!el.length || cfg.overwrite) {
            if (cfg.overwrite) {
                $(context).empty();
            }
            self.renderHtml(tmpl(_data), context);
            el = $(sel);
        }
        callback && callback.call(this, {el: el});
    };
    module.exports = common;
})();